package com.hdu.careerplan.service.Impl;

import com.alibaba.fastjson.JSON;
import com.hdu.careerplan.configuration.FilepathConfiguration;
import com.hdu.careerplan.enums.CommandCode;
import com.hdu.careerplan.enums.CommandPatternEnum;
import com.hdu.careerplan.pojo.dto.CityJobDTO;
import com.hdu.careerplan.pojo.dto.CityJobChoiceListDTO;
import com.hdu.careerplan.pojo.dto.TrendTimeDTO;
import com.hdu.careerplan.pojo.pythonData.SalaryData;
import com.hdu.careerplan.pojo.pythonData.TechListData;
import com.hdu.careerplan.pojo.vo.TechListDataVO;


import com.hdu.careerplan.pojo.vo.TrendVO;
import com.hdu.careerplan.service.DataAnalysisService;
import com.hdu.careerplan.util.MongoDocumentStructureUtil;
import com.hdu.careerplan.util.PythonJsonUtil;
import com.hdu.careerplan.util.PythonProcessUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@Service
public class DataAnalysisServiceImpl implements DataAnalysisService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 初始用户在选择了一个城市和一个岗位的时候，返回对应的值
     *
     * @param cityJobDTO 前端传值为城市和岗位名
     * @return 返回一个城市一个岗位的相关信息
     * @author ZHR
     */
    @Override
    public SalaryData salaryInitialChoice(CityJobDTO cityJobDTO) {
        String jobName = cityJobDTO.getJobName();
        String city = cityJobDTO.getCity();
        Criteria criteria = new Criteria("jobName").is(jobName).and("region").is(city);
        Query query = new Query(criteria);
        return mongoTemplate.findOne(query, SalaryData.class);
    }


    /**
     * 一个城市不同岗位的数据，和一个岗位不同城市的数据
     *
     * @param flag                 0：一个城市不同岗位的数据；1：一个岗位不同城市的数据
     * @param cityJobChoiceListDTO 城市 岗位 列表
     * @return 薪资列表
     * @author JacksonZHR
     */
    @Override
    public List<SalaryData> compareSalary(int flag, CityJobChoiceListDTO cityJobChoiceListDTO) {

        List<String> choiceList = cityJobChoiceListDTO.getChoiceList();

        String mainValue = null;
        String mainKey = null;
        String listKey = null;
        if (flag == 0) {
            mainKey = "region";
            mainValue = cityJobChoiceListDTO.getCity();
            listKey = "jobName";
        } else {
            mainKey = "jobName";
            mainValue = cityJobChoiceListDTO.getJobName();
            listKey = "region";
            choiceList.add("全国");
        }


        Criteria mainCriteria = new Criteria(mainKey).is(mainValue);
        Criteria listCriteria = Criteria.where(listKey).in(choiceList);
        Query query = new Query();
        query.addCriteria(mainCriteria).addCriteria(listCriteria);
        return mongoTemplate.find(query, SalaryData.class);


    }


    /**
     * 初始用户在选择了一个城市和一个岗位的时候，返回对应的值
     *
     * @param cityJobDTO 前端传值为城市和岗位名
     * @return 返回一个城市一个岗位的相关信息
     * @author JacksonZHR
     */
    @Override
    public TechListDataVO techInitialChoice(CityJobDTO cityJobDTO) throws IOException, InterruptedException {
        String jobName = cityJobDTO.getJobName();
        String city = cityJobDTO.getCity();

        Criteria criteria = new Criteria("jobName").is(jobName).and("region").is(city);
        Query query = new Query(criteria);
        TechListData techListData = mongoTemplate.findOne(query, TechListData.class);
        if (techListData == null) return null;
        else return new TechListDataVO(techListData);

//        String pythonCommand = PythonProcessUtil.generatePythonCommand(FilepathConfiguration.pyDirPath, FilepathConfiguration.pyName,
//                CommandPatternEnum.INITIAL_TECH_CHOICE, CommandCode.TECH.getOptionCode(), city, jobName);
//
//        String output = PythonProcessUtil.startPythonProcess(pythonCommand);
//        String jsonFromPythonOutput = PythonJsonUtil.getJsonFromPythonOutput(output);
//
//        // TODO ZHR [2024.1.2] 如何优雅的从set当中取值
//        if (PythonJsonUtil.jsonExists(jsonFromPythonOutput)) {
//            Map<String, List<String>> map = JSON.parseObject(jsonFromPythonOutput, Map.class);
//            Object[] array = map.keySet().toArray();
//
//            return new TechListDataVO(city, jobName, map.get(array[0]));
//        } else return null;

    }

    /**
     * 一个城市不同岗位的数据，和一个岗位不同城市的数据
     *
     * @param flag                 0：一个城市不同岗位的数据；1：一个岗位不同城市的数据
     * @param cityJobChoiceListDTO 城市 岗位 列表
     * @return 技术列表
     * @author JacksonZHR
     */
    @Override
    public List<TechListDataVO> compareTech(int flag, CityJobChoiceListDTO cityJobChoiceListDTO) throws IOException, InterruptedException {
        List<String> choiceList = cityJobChoiceListDTO.getChoiceList();

        String mainValue = null;
        String mainKey = null;
        String listKey = null;
        if (flag == 0) {
            mainKey = "region";
            mainValue = cityJobChoiceListDTO.getCity();
            listKey = "jobName";
        } else {
            mainKey = "jobName";
            mainValue = cityJobChoiceListDTO.getJobName();
            listKey = "region";
            choiceList.add("全国");
        }


        Criteria mainCriteria = new Criteria(mainKey).is(mainValue);
        Criteria listCriteria = Criteria.where(listKey).in(choiceList);
        Query query = new Query();
        query.addCriteria(mainCriteria).addCriteria(listCriteria);
        List<TechListData> techListData = mongoTemplate.find(query, TechListData.class);
        ArrayList<TechListDataVO> techListVO = new ArrayList<>();
        for (TechListData techData : techListData) {
            techListVO.add(new TechListDataVO(techData));
        }
        return techListVO;


//        String jobName = cityJobChoiceListDTO.getJobName();
//        String city = cityJobChoiceListDTO.getCity();
//        List<String> choiceList = cityJobChoiceListDTO.getChoiceList();
//        List<TechListDataVO> techListDataArrayListVO = new ArrayList<>();
//
//        StringBuilder pythonCommand = new StringBuilder();
//
//        String temp;
//        if(!choiceList.isEmpty()) {
//            temp = choiceList.get(0);
//        }
//        else {
//            if (flag == 0) temp = jobName;
//            else temp = city;
//        }
//
//        if (flag == 0) {
//            pythonCommand.append(PythonProcessUtil.generatePythonCommand(FilepathConfiguration.pyDirPath, FilepathConfiguration.pyName,
//                    CommandPatternEnum.COMPARE_TECH_JOB, CommandCode.TECH.getOptionCode(), city, jobName, "2", temp));
//        } else if (flag == 1) {
//            pythonCommand.append(PythonProcessUtil.generatePythonCommand(FilepathConfiguration.pyDirPath, FilepathConfiguration.pyName,
//                    CommandPatternEnum.COMPARE_TECH_REGION, CommandCode.TECH.getOptionCode(), city, jobName, "3", temp));
//        }
//
//        // TODO ZHR [2023.12.27] 对拼接字符串的命令的改进
//        for (int i = 1; i < choiceList.size(); i++) {
//            pythonCommand.append(" ").append(choiceList.get(i));
//        }
//
//        String output = PythonProcessUtil.startPythonProcess(pythonCommand.toString());
//        String jsonFromPythonOutput = PythonJsonUtil.getJsonFromPythonOutput(output);
//        System.out.println(jsonFromPythonOutput);
//
//
//        // TODO ZHR [2024.1.2] 强制转换太多了
//        if (PythonJsonUtil.jsonExists(jsonFromPythonOutput)) {
//            Map<String, Object> stringObjectMap = PythonJsonUtil.jsonToMap(jsonFromPythonOutput);
//            if (flag == 0) {
//                for (String jobKey : stringObjectMap.keySet()) {
//                    techListDataArrayListVO.add(new TechListDataVO(city, jobKey, (List<String>) stringObjectMap.get(jobKey)));
//                }
//            } else {
//                for (String regionKey : stringObjectMap.keySet()) {
//                    techListDataArrayListVO.add(new TechListDataVO(regionKey, jobName,  (List<String>) stringObjectMap.get(regionKey)));
//                }
//            }
//            return techListDataArrayListVO;
//
//        } else return null;

    }

    @Override
    public List<TrendVO> getAndGroupTrendDate(TrendTimeDTO trendTimeDTO) {
        // 1. 匹配选择方向与时间范围
        MatchOperation match = Aggregation.match(Criteria.where("direction").is(trendTimeDTO.getDirection())
                .and("date").gte(trendTimeDTO.getFrom()).lte(trendTimeDTO.getTo()));


        // 2. 去除重复的日期数据
        GroupOperation groupOperationDistinct = Aggregation.group("date").first("job_num").as("job_num").first("mean").as("mean");

        // 3. 取出年月日
        ProjectionOperation projectionTime = Aggregation.project()
                .and("_id").as("date")
                .and("job_num").as("job_num")
                .and("mean").as("mean")
                .andExpression("toInt(substr(_id, 0, 4))").as("year")
                .andExpression("toInt(substr(_id, 5, 2))").as("month")
                .andExpression("toInt(substr(_id, 8, 2))").as("day");

        // 4. 按照年/月/日聚合
        GroupOperation groupYear = Aggregation.group("year").avg("mean").as("salary").avg("job_num").as("jobCnt");
        GroupOperation groupMonth = Aggregation.group("year", "month").avg("mean").as("salary").avg("job_num").as("jobCnt");
        GroupOperation groupDay = Aggregation.group("year", "month", "day").avg("mean").as("salary").avg("job_num").as("jobCnt");

        // 5. 排序
        SortOperation sort = Aggregation.sort(Sort.Direction.ASC, "_id");

        // 6. 转换为前端指定格式
        if (trendTimeDTO.getTimeUnit().equals("day")) {
            Aggregation aggregation = Aggregation.newAggregation(match, groupOperationDistinct,
                    projectionTime, groupDay, sort, MongoDocumentStructureUtil.createDateProjectionDay());
            return mongoTemplate.aggregate(aggregation, "trend", TrendVO.class).getMappedResults();
        }
        else if(trendTimeDTO.getTimeUnit().equals("month")) {
            Aggregation aggregation = Aggregation.newAggregation(match, groupOperationDistinct,
                    projectionTime, groupMonth, sort, MongoDocumentStructureUtil.createDateProjectionMonth());
            return mongoTemplate.aggregate(aggregation, "trend", TrendVO.class).getMappedResults();
        }
        else if (trendTimeDTO.getTimeUnit().equals("year")) {
            Aggregation aggregation = Aggregation.newAggregation(match, groupOperationDistinct,
                    projectionTime, groupYear, sort, MongoDocumentStructureUtil.createDateProjectionYear());
            return mongoTemplate.aggregate(aggregation, "trend", TrendVO.class).getMappedResults();
        }
        else return null;
    }
}
